package jmpo.mth;
/**
 * Удобным средством для выполнения задач в фоне, если им не нужна 
 * сложная синхронизация, являются специально заданные провайдеры
 * потоков.
 * Стандартная библиотека поддерживает два основных интерфейса:
 *     Executor - интерфейс с одним единственным методом execute, 
 *     который принимает Runnable и гарантирует его выполнение в будущем.
 * 
 *     ExecutorService - более богатый интерфейс, который позволяет принимать
 *     задачи с возвращаемыми значениями и исключениями, реализующими
 *     интерфейс Callable.
 * 
 * Executors - это класс со статическими методами, который позволяет получить
 * готовые ExecutorService для различных задач.
 */

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Просуммируем данные в нескольких списках с помощью ExecutorService.
 */
final class ListSumExample {
    private static final class SumTask implements Callable<Long> {
        public SumTask(List<Long> lst) {
            this.lst = lst;
        }

        @Override
        public Long call() {
            Long sum = 0l;
            for (var l : lst)
                sum += l;
            return sum;
        }
        
        private final List<Long> lst;
    }

    public static void test() {
        ExecutorService service = Executors.newFixedThreadPool(3);
        List<Long> l1 = List.of(1l, 2l, 3l, 4l, 5l);
        List<Long> l2 = List.of(6l, 7l, 8l, 9l, 10l);
        List<Long> l3 = List.of(11l, 12l, 13l, 14l, 15l, 16l);

        List<Callable<Long>> tasks = List.of(new SumTask(l1), new SumTask(l2), new SumTask(l3));
        List<Future<Long>> answers = new ArrayList<>();
        for (var task : tasks)
            answers.add(service.submit(task));
        
        try {
            for (var f : answers) {
                System.out.println(f.get());
            }
        } catch (InterruptedException e) {
            System.out.println("Unexpected interruption");
        } catch (ExecutionException e) {
            System.out.println(e.getMessage());
        } finally {
            service.shutdown();
        }
    }
}

public class ExecuterExample {
    public static void main(String[] args) {
        if (true) ListSumExample.test();
    }
}
